﻿using System;
using System.ComponentModel;
using System.Windows.Data;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Kinect;
using Microsoft.Kinect.Toolkit;
using Fizbin.Kinect.Gestures;
using Microsoft.Samples.Kinect.WpfViewers;
using Fleck;
using KinectServer;
using System.Threading;

namespace kinectServer
{

    public partial class MainWindow : Window
    {
        int ctr = 0;
        private readonly KinectSensorChooser sensorChooser = new KinectSensorChooser();

        private GestureController gestureController;

        private Skeleton[] skeletons = new Skeleton[0];

        protected List<IWebSocketConnection> _sockets;

        protected List<Skeleton> _users;
        protected static Skeleton[] _skeletons = new Skeleton[6];
        static byte[] _pixels;

        static bool _reconheceu = false;
        protected WebSocketServer server;

        public MainWindow()
        {
            DataContext = this;

            InitializeComponent();

            // initialize the Kinect sensor manager
            KinectSensorManager = new KinectSensorManager();
            KinectSensorManager.KinectSensorChanged += this.KinectSensorChanged;

            // locate an available sensor
            sensorChooser.Start();

            // bind chooser's sensor value to the local sensor manager
            var kinectSensorBinding = new Binding("Kinect") { Source = this.sensorChooser };
            BindingOperations.SetBinding(this.KinectSensorManager, KinectSensorManager.KinectSensorProperty, kinectSensorBinding);

            /** Cria lista de conexoes de clientes */
            _sockets = new List<IWebSocketConnection>();
            /** Instancia servidor de socketes */
            server = new WebSocketServer("ws://localhost:8181");

            /** Definicao do comportamento do servidor socket */
            server.Start(socket =>
            {
                socket.OnOpen = () =>
                {
                    /** Adiciona o clinte na lista */
                    _sockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    /** Remove o cliente da lista */
                    _sockets.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                };
            });
          
        }

        /** Evento executado quando kinect muda de estado */
        private void KinectSensorChanged(object sender, KinectSensorManagerEventArgs<KinectSensor> args)
        {
            if (null != args.OldValue)
                UninitializeKinectServices(args.OldValue);

            if (null != args.NewValue)
                InitializeKinectServices(KinectSensorManager, args.NewValue);
        }

        /** Metodo iniciar o servico do kinect*/
        private void InitializeKinectServices(KinectSensorManager kinectSensorManager, KinectSensor sensor)
        {
            /** Define a resolucao da camera de cor */
            kinectSensorManager.ColorFormat = ColorImageFormat.RgbResolution640x480Fps30;
            /** Habilita a camera de cor */
            kinectSensorManager.ColorStreamEnabled = true;
            /** Habilita a sensor de profundidade */
            kinectSensorManager.DepthStreamEnabled = true;
            /** Parametros de correcao */
            kinectSensorManager.TransformSmoothParameters =
                new TransformSmoothParameters
                {
                    Smoothing = 0.5f,
                    Correction = 0.5f,
                    Prediction = 0.5f,
                    JitterRadius = 0.05f,
                    MaxDeviationRadius = 0.04f
                };

            /** Define a funcao a ser executada quando o sensor capturar um frame*/

            sensor.SkeletonFrameReady += OnSkeletonFrameReady;
            /** Habilita a captura de esqueletos*/
            kinectSensorManager.SkeletonStreamEnabled = true;

            /** Inicia o reconhecedor de gestos*/
            gestureController = new GestureController();
            /** Define o metodo a ser executado ao reconhecer um gesto*/
            gestureController.GestureRecognized += OnGestureRecognized;

            /** Habilita o sensor kinect*/
            kinectSensorManager.KinectSensorEnabled = true;

            /** 
            if (!kinectSensorManager.KinectSensorAppConflict)
            {
                // addition configuration, as needed
            }
             */ 
        }

        // Kinect enabled apps should uninitialize all Kinect services that were initialized in InitializeKinectServices() here.
        private void UninitializeKinectServices(KinectSensor sensor)
        {

        }

        public static readonly DependencyProperty KinectSensorManagerProperty =
           DependencyProperty.Register(
               "KinectSensorManager",
               typeof(KinectSensorManager),
               typeof(MainWindow),
               new PropertyMetadata(null));

        public KinectSensorManager KinectSensorManager
        {
            get { return (KinectSensorManager)GetValue(KinectSensorManagerProperty); }
            set { SetValue(KinectSensorManagerProperty, value); }
        }

        // Event implementing INotifyPropertyChanged interface.
        public event PropertyChangedEventHandler PropertyChanged;

        /**
         * Quando o kinect reconhecer um jogador esse metodo sera invocado
         * metodo atualiza o vetor de jogadores com os pontos existentes no frame corrente
         * 
         */
        private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            _users = new List<Skeleton>();
            using (SkeletonFrame frame = e.OpenSkeletonFrame())
            {
                if (frame == null)
                    return;
                frame.CopySkeletonDataTo(_skeletons);
                bool envia = false;
                foreach (var user in _skeletons)
                {
                    if (user.TrackingState == SkeletonTrackingState.Tracked)
                    {
                        envia = true;
                        _users.Add(user);
                        gestureController.UpdateAllGestures(user);
                    }
                }
                /** Envia os dados de todos os usuario para os clientes conectados ao servidor*/
                if (envia)
                {
                    string json = _users.Serialize();   
                    sendInfoToClientes(json);   
                }
            }
            //// 2. Tratamento de imagem .
            //using (var frame = e.OpenColorImageFrame())
            //{
            //    if (frame != null)
            //    {
            //        _pixels = new byte[frame.PixelDataLength];

            //        frame.CopyPixelDataTo(_pixels);

            //        foreach (var socket in _sockets)
            //        {
            //            socket.Send(System.Text.UTF8Encoding.UTF8.GetString(_pixels));
            //        }
            //    }
            //}
        }

        /** Metodo envia uma mensagem no formato json para todos os clientes*/
        private void sendInfoToClientes(string json) {
            //dispara para todos os sockets conectados
            foreach (var socket in _sockets)
            {
                socket.Send(json);
            }
        }
        /**
         * Adicionar a lista completa de eventos e o envio para o socket cliente neste metodo
         */
        private void OnGestureRecognized(object sender, GestureEventArgs e)
        {
            string evento = "";
            switch (e.GestureType)
            {
                case GestureType.Hadouken:
                    {
                        evento = "hadouken";
                    }
                    break;
                case GestureType.SwipeLeft:
                    {
                        evento = "swipe_left";
                    }
                    break;
                case GestureType.SwipeRight:
                    {
                        evento = "swipe_right";
                    }
                    break;
                case GestureType.Menu:
                    {
                        evento = "menu";
                    }
                    break;
                case GestureType.WaveRight:
                    {
                        evento = "wave_right";
                    }
                    break;
                case GestureType.WaveLeft:
                    {
                        evento = "wave_left";
                    }
                    break;
                case GestureType.JoinedHands:
                    {
                        evento = "joined_hands";
                    }
                    break;
                case GestureType.ZoomIn:
                    {
                        evento = "zoom_in";
                    }
                    break;
                case GestureType.ZoomOut:
                    {
                        evento = "zoom_out";
                    }
                    break;
                default:
                    break;

            }
            JSONEvents je = new JSONEvents(evento);
            //sendInfoToClientes(je.Serialize());
            sendInfoToClientes("{\"name\":\""+evento+"\"}");
        }

        public void Window_Loaded(object sender, RoutedEventArgs e) { }
       
        public void textBox1_TextChanged() { }

        private void myImage_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
        }

        private void Window_Loaded()
        {
        }


        //private string _gesture;
        //public String Gesture
        //{
        //    get { return _gesture; }
        //    private set
        //    {
        //        if (_gesture == value)
        //            return;
        //        _gesture = value;
        //        if (this.PropertyChanged != null)
        //            PropertyChanged(this, new PropertyChangedEventArgs("Gesture"));
        //    }
        //}

    }
}